<!DOCTYPE HTML>
<html lang="zh-Hans" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>Sizedness in Rust - Rust 优秀博文</title>


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../../favicon.svg">
        <link rel="shortcut icon" href="../../favicon.png">
        <link rel="stylesheet" href="../../css/variables.css">
        <link rel="stylesheet" href="../../css/general.css">
        <link rel="stylesheet" href="../../css/chrome.css">
        <link rel="stylesheet" href="../../css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../../fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../../highlight.css">
        <link rel="stylesheet" href="../../tomorrow-night.css">
        <link rel="stylesheet" href="../../ayu-highlight.css">

        <!-- Custom theme stylesheets -->

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">1.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow.html"><strong aria-hidden="true">1.1.</strong> Rust Concept Clarification Deref vs AsRef vs Borrow vs Cow</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Deref_AsRef_Borrow_Cow释义.html"><strong aria-hidden="true">1.2.</strong> Deref AsRef Borrow Cow 释义</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然.html"><strong aria-hidden="true">1.3.</strong> Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Cow类型有什么用？详解Cow及其用途/Rust的Cow类型有什么用？详解Cow及其用途.html"><strong aria-hidden="true">1.4.</strong> Rust的Cow类型有什么用？详解Cow及其用途</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/判别Fn、FnMut、FnOnce的标准/判别Fn、FnMut、FnOnce的标准.html"><strong aria-hidden="true">1.5.</strong> 判别Fn、FnMut、FnOnce的标准</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/一行代码告诉你内部可变性的真相(UnsafeCell)/一行代码告诉你内部可变性的真相(UnsafeCell).html"><strong aria-hidden="true">1.6.</strong> 一行代码告诉你内部可变性的真相(UnsafeCell)</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Tour_of_Rust's_Standard_Library_Traits/Tour_of_Rust's_Standard_Library_Traits.html"><strong aria-hidden="true">1.7.</strong> Tour of Rust's Standard Library Traits</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/逆变、协变与子类型，以及Rust/逆变、协变与子类型，以及Rust.html"><strong aria-hidden="true">1.8.</strong> 逆变、协变与子类型，以及Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust自引用结构、Pin与Unpin/Rust自引用结构、Pin与Unpin.html"><strong aria-hidden="true">1.9.</strong> Rust自引用结构、Pin与Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/为什么Rust需要Pin,Unpin/为什么Rust需要Pin,Unpin.html"><strong aria-hidden="true">1.10.</strong> 译：为什么 Rust 需要 Pin, Unpin ？</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/定海神针Pin和Unpin/定海神针Pin和Unpin.html"><strong aria-hidden="true">1.11.</strong> 译：定海神针 Pin 和 Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/sizedness-in-rust/sizedness-in-rust.html" class="active"><strong aria-hidden="true">1.12.</strong> Sizedness in Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust生命周期集大成者PhantomData〈T〉/Rust生命周期集大成者PhantomData〈T〉.html"><strong aria-hidden="true">1.13.</strong> Rust生命周期集大成者 PhantomData&lt;T&gt;</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操_Part_0.html"><strong aria-hidden="true">1.14.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操 Part 0</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：GAT实现引用类型关联_Part_1.html"><strong aria-hidden="true">1.15.</strong> 数据库表达式执行的黑魔法：GAT实现引用类型关联 Part 1</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用HRTB写bound_Part_2.html"><strong aria-hidden="true">1.16.</strong> 数据库表达式执行的黑魔法：用HRTB写bound Part 2</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码_Part_3_&_4.html"><strong aria-hidden="true">1.17.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码 Part 3 & 4</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化_Part_5_&_6.html"><strong aria-hidden="true">1.18.</strong> 数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化 Part 5 & 6</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型_Part_7.html"><strong aria-hidden="true">1.19.</strong> 数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型 Part 7</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">2.</strong> 生命周期</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../02_生命周期/Rust中的生命周期——从StrSplit实例说开去/Rust中的生命周期——从StrSplit实例说开去.html"><strong aria-hidden="true">2.1.</strong> Rust中的生命周期——从StrSplit实例说开去</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/与ChatGPT深度对话来学Rust生命周期/与ChatGPT深度对话来学Rust生命周期.html"><strong aria-hidden="true">2.2.</strong> 与ChatGPT深度对话来学Rust生命周期</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（1）/进击的Rust生命周期——early_bound与late_bound（1）.html"><strong aria-hidden="true">2.3.</strong> 进击的Rust生命周期——early_bound与late_bound（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（2）/进击的Rust生命周期——early_bound与late_bound（2）.html"><strong aria-hidden="true">2.4.</strong> 进击的Rust生命周期——early_bound与late_bound（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（1）/进击的Rust生命周期——一力降十会的MIR（1）.html"><strong aria-hidden="true">2.5.</strong> 进击的Rust生命周期——一力降十会的MIR（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（2）/进击的Rust生命周期——一力降十会的MIR（2）.html"><strong aria-hidden="true">2.6.</strong> 进击的Rust生命周期——一力降十会的MIR（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Common_Rust_Lifetime_Misconceptions/Common_Rust_Lifetime_Misconceptions.html"><strong aria-hidden="true">2.7.</strong> Common Rust Lifetime Misconceptions</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Rust生命周期常见误区/Rust生命周期常见误区.html"><strong aria-hidden="true">2.8.</strong> 译：Rust生命周期常见误区</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">3.</strong> 无畏并发</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../05_无畏并发/简单写个Rust无锁队列/简单写个Rust无锁队列.html"><strong aria-hidden="true">3.1.</strong> 简单写个Rust无锁队列</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——混合自旋锁/进击的Rust多线程——混合自旋锁.html"><strong aria-hidden="true">3.2.</strong> 进击的Rust多线程——混合自旋锁</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/An_unsafe_tour_of_Rust's_Send_and_Sync/An_unsafe_tour_of_Rust's_Send_and_Sync.html"><strong aria-hidden="true">3.3.</strong> An unsafe tour of Rust's Send and Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——Send与Sync/进击的Rust多线程——Send与Sync.html"><strong aria-hidden="true">3.4.</strong> 进击的Rust多线程——Send与Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——离经叛道的PhantomData/进击的Rust多线程——离经叛道的PhantomData.html"><strong aria-hidden="true">3.5.</strong> 进击的Rust多线程——离经叛道的PhantomData</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust_Async_Pin概念解析/Rust_Async_Pin概念解析.html"><strong aria-hidden="true">3.6.</strong> Rust Async: Pin概念解析</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust和C++的并发库对比/Rust和C++的并发库对比.html"><strong aria-hidden="true">3.7.</strong> 译：Rust 和 C++ 的并发库对比</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust原子类型和内存排序/Rust原子类型和内存排序.html"><strong aria-hidden="true">3.8.</strong> Rust原子类型和内存排序</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">4.</strong> 网络编程</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../06_网络编程/从编解码层面理解WebSocket_手写一个WebSocket/从编解码层面理解WebSocket_手写一个WebSocket.html"><strong aria-hidden="true">4.1.</strong> 从编解码层面理解WebSocket 手写一 个WebSocket</a></li><li class="chapter-item expanded "><a href="../../06_网络编程/透过Rust探索系统的本原：网络篇/透过Rust探索系统的本原：网络篇.html"><strong aria-hidden="true">4.2.</strong> 透过Rust探索系统的本原：网络篇</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">5.</strong> 轮子系列</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../07_轮子系列/700行Rust写一个内存分配器/700行Rust写一个内存分配器.html"><strong aria-hidden="true">5.1.</strong> 700行Rust写一个内存分配器</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust：网络库的实现思路/Rust：网络库的实现思路.html"><strong aria-hidden="true">5.2.</strong> Rust：网络库的实现思路</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust异步运行时基础部件/Rust异步运行时基础部件.html"><strong aria-hidden="true">5.3.</strong> Rust异步运行时基础部件</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（1）.html"><strong aria-hidden="true">5.4.</strong> 使用Rust+epoll编写异步IO框架（1）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（2）.html"><strong aria-hidden="true">5.5.</strong> 使用Rust+epoll编写异步IO框架（2）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（3）.html"><strong aria-hidden="true">5.6.</strong> 使用Rust+epoll编写异步IO框架（3）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day1.html"><strong aria-hidden="true">5.7.</strong> 用rust从零开发一套web框架：day1</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day2.html"><strong aria-hidden="true">5.8.</strong> 用rust从零开发一套web框架：day2</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day3.html"><strong aria-hidden="true">5.9.</strong> 用rust从零开发一套web框架：day3</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day4.html"><strong aria-hidden="true">5.10.</strong> 用rust从零开发一套web框架：day4</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day5.html"><strong aria-hidden="true">5.11.</strong> 用rust从零开发一套web框架：day5</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">6.</strong> 奇技淫巧</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Copy-On-Write是不是优化？/Copy-On-Write是不是优化？.html"><strong aria-hidden="true">6.1.</strong> 译：Copy-On-Write是不是优化？</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/揭秘神奇的Rust_Axum风格的函数实现/揭秘神奇的Rust_Axum风格的函数实现.html"><strong aria-hidden="true">6.2.</strong> 译：揭秘神奇的 Rust Axum 风格的函数实现</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/“变长参数”函数与回调/“变长参数”函数与回调.html"><strong aria-hidden="true">6.3.</strong> “变长参数”函数与回调</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Rust字符串格式化的幕后：format_args!()/Rust字符串格式化的幕后：format_args!().html"><strong aria-hidden="true">6.4.</strong> 译：Rust字符串格式化的幕后：format_args!()</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/给Rust带来一点C++特产/给Rust带来一点C++特产.html"><strong aria-hidden="true">6.5.</strong> 给Rust带来一点C++特产</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/一步步实现_Rust_Bevy_ECS_的_System_简化版本/一步步实现_Rust_Bevy_ECS_的_System_简化版本.html"><strong aria-hidden="true">6.6.</strong> 一步步实现 Rust Bevy ECS 的 System 简化版本</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples.html"><strong aria-hidden="true">6.7.</strong> Exploring Design Patterns in Rust with Algorithmic Trading Examples</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">7.</strong> 源码分析</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：bytes源码分析/Rust并发：bytes源码分析.html"><strong aria-hidden="true">7.1.</strong> Rust并发：bytes源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库Arc源码分析/Rust并发：标准库Arc源码分析.html"><strong aria-hidden="true">7.2.</strong> Rust并发：标准库Arc源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库sync_Once源码分析/Rust并发：标准库sync_Once源码分析.html"><strong aria-hidden="true">7.3.</strong> Rust并发：标准库sync::Once源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：引用计数Rc/Rust源码阅读：引用计数Rc.html"><strong aria-hidden="true">7.4.</strong> Rust源码阅读：引用计数Rc</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：Cell、RefCell与内部可变性/Rust源码阅读：Cell、RefCell与内部可变性.html"><strong aria-hidden="true">7.5.</strong> Rust源码阅读： Cell、RefCell与内部可变性</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/关于_Rust_的_UnsafeCell、Cell_与_RefCell/关于_Rust_的_UnsafeCell、Cell_与_RefCell.html"><strong aria-hidden="true">7.6.</strong> 关于 Rust 的 UnsafeCell、Cell 与 RefCell</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Async_async-stream源码分析/Rust_Async_async-stream源码分析.html"><strong aria-hidden="true">7.7.</strong> Rust Async: async-stream源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/走进Tokio的异步世界/走进Tokio的异步世界.html"><strong aria-hidden="true">7.8.</strong> 走进 Tokio 的异步世界</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html"><strong aria-hidden="true">7.9.</strong> tokio.rs runtime 的实现</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/Tokio_internals.html"><strong aria-hidden="true">7.10.</strong> Tokio internals</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/译文：Tokio內部机制.html"><strong aria-hidden="true">7.11.</strong> 译：Tokio 内部机制</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Axum_HTTP_框架的架构分析/Rust_Axum_HTTP_框架的架构分析.html"><strong aria-hidden="true">7.12.</strong> Rust Axum HTTP 框架的架构分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/安利一个Rust_Game_Engine：Bevy--ECS部分/安利一个Rust_Game_Engine：Bevy--ECS部分.html"><strong aria-hidden="true">7.13.</strong> 安利一个Rust Game Engine：Bevy--ECS部分</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_解析之任务调度/Tokio_解析之任务调度.html"><strong aria-hidden="true">7.14.</strong> Tokio 解析之任务调度</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">8.</strong> 生态观察</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../11_生态观察/Rust_web_frameworks_have_subpar_error_reporting/Rust_web_frameworks_have_subpar_error_reporting.html"><strong aria-hidden="true">8.1.</strong> Rust web frameworks have subpar error reporting</a></li><li class="chapter-item expanded "><a href="../../11_生态观察/SeaORM：要做Rust版本的ActiveRecord/SeaORM：要做Rust版本的ActiveRecord.html"><strong aria-hidden="true">8.2.</strong> SeaORM：要做Rust版本的ActiveRecord</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">9.</strong> 死灵终极</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_总述.html"><strong aria-hidden="true">9.1.</strong> 译：Learn Rust the Dangerous Way 总述</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_0.html"><strong aria-hidden="true">9.2.</strong> 译：Learn Rust the Dangerous Way 0</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_1.html"><strong aria-hidden="true">9.3.</strong> 译：Learn Rust the Dangerous Way 1</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_2.html"><strong aria-hidden="true">9.4.</strong> 译：Learn Rust the Dangerous Way 2</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_3.html"><strong aria-hidden="true">9.5.</strong> 译：Learn Rust the Dangerous Way 3</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_4.html"><strong aria-hidden="true">9.6.</strong> 译：Learn Rust the Dangerous Way 4</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_5.html"><strong aria-hidden="true">9.7.</strong> 译：Learn Rust the Dangerous Way 5</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（一）.html"><strong aria-hidden="true">9.8.</strong> Unsafe Rust 随堂小测（一）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（二）.html"><strong aria-hidden="true">9.9.</strong> Unsafe Rust 随堂小测（二）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（三）.html"><strong aria-hidden="true">9.10.</strong> Unsafe Rust 随堂小测（三）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测参考答案.html"><strong aria-hidden="true">9.11.</strong> Unsafe Rust 随堂小测参考答案</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Rust 优秀博文</h1>

                    <div class="right-buttons">
                        <a href="../../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="sizedness-in-rust"><a class="header" href="#sizedness-in-rust">Sizedness in Rust</a></h1>
<p>作者：<a href="https://github.com/pretzelhammer">pretzelhammer</a></p>
<p>原载：<a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/sizedness-in-rust.md">https://github.com/pretzelhammer/rust-blog/blob/master/posts/sizedness-in-rust.md</a></p>
<p><em>22 July 2020 · #rust · #sizedness</em></p>
<p><strong>Table of Contents</strong></p>
<ul>
<li><a href="#intro">Intro</a></li>
<li><a href="#sizedness">Sizedness</a></li>
<li><a href="#sized-trait"><code>Sized</code> Trait</a></li>
<li><a href="#sized-in-generics"><code>Sized</code> in Generics</a></li>
<li><a href="#unsized-types">Unsized Types</a>
<ul>
<li><a href="#slices">Slices</a></li>
<li><a href="#trait-objects">Trait Objects</a></li>
<li><a href="#trait-object-limitations">Trait Object Limitations</a>
<ul>
<li><a href="#cannot-cast-unsized-types-to-trait-objects">Cannot Cast Unsized Types to Trait Objects</a></li>
<li><a href="#cannot-create-multi-trait-objects">Cannot create Multi-Trait Objects</a></li>
</ul>
</li>
<li><a href="#user-defined-unsized-types">User-Defined Unsized Types</a></li>
</ul>
</li>
<li><a href="#zero-sized-types">Zero-Sized Types</a>
<ul>
<li><a href="#unit-type">Unit Type</a></li>
<li><a href="#user-defined-unit-structs">User-Defined Unit Structs</a></li>
<li><a href="#never-type">Never Type</a></li>
<li><a href="#user-defined-pseudo-never-types">User-Defined Pseudo Never Types</a></li>
<li><a href="#phantomdata">PhantomData</a></li>
</ul>
</li>
<li><a href="#conclusion">Conclusion</a></li>
<li><a href="#discuss">Discuss</a></li>
<li><a href="#notifications">Notifications</a></li>
<li><a href="#further-reading">Further Reading</a></li>
</ul>
<h2 id="intro"><a class="header" href="#intro">Intro</a></h2>
<p>Sizedness is lowkey one of the most important concepts to understand in Rust. It intersects a bunch of other language features in often subtle ways and only rears its ugly head in the form of <em>&quot;x doesn't have size known at compile time&quot;</em> error messages which every Rustacean is all too familiar with. In this article we'll explore all flavors of sizedness from sized types, to unsized types, to zero-sized types while examining their use-cases, benefits, pain points, and workarounds.</p>
<p>Table of phrases I use and what they're supposed to mean:</p>
<div class="table-wrapper"><table><thead><tr><th>Phrase</th><th>Shorthand for</th></tr></thead><tbody>
<tr><td>sizedness</td><td>property of being sized or unsized</td></tr>
<tr><td>sized type</td><td>type with a known size at compile time</td></tr>
<tr><td>1) unsized type <em>or</em><br>2) DST</td><td>dynamically-sized type, i.e. size not known at compile time</td></tr>
<tr><td>?sized type</td><td>type that may or may not be sized</td></tr>
<tr><td>unsized coercion</td><td>coercing a sized type into an unsized type</td></tr>
<tr><td>ZST</td><td>zero-sized type, i.e. instances of the type are 0 bytes in size</td></tr>
<tr><td>width</td><td>single unit of measurement of pointer width</td></tr>
<tr><td>1) thin pointer <em>or</em><br>2) single-width pointer</td><td>pointer that is <em>1 width</em></td></tr>
<tr><td>1) fat pointer <em>or</em><br>2) double-width pointer</td><td>pointer that is <em>2 widths</em></td></tr>
<tr><td>1) pointer <em>or</em><br>2) reference</td><td>some pointer of some width, width will be clarified by context</td></tr>
<tr><td>slice</td><td>double-width pointer to a dynamically sized view into some array</td></tr>
</tbody></table>
</div>
<h2 id="sizedness"><a class="header" href="#sizedness">Sizedness</a></h2>
<p>In Rust a type is sized if its size in bytes can be determined at compile-time. Determining a type's size is important for being able to allocate enough space for instances of that type on the stack. Sized types can be passed around by value or by reference. If a type's size can't be determined at compile-time then it's referred to as an unsized type or a DST, Dynamically-Sized Type. Since unsized types can't be placed on the stack they can only be passed around by reference. Some examples of sized and unsized types:</p>
<pre><pre class="playground"><code class="language-rust">use std::mem::size_of;

fn main() {
    // primitives
    assert_eq!(4, size_of::&lt;i32&gt;());
    assert_eq!(8, size_of::&lt;f64&gt;());

    // tuples
    assert_eq!(8, size_of::&lt;(i32, i32)&gt;());

    // arrays
    assert_eq!(0, size_of::&lt;[i32; 0]&gt;());
    assert_eq!(12, size_of::&lt;[i32; 3]&gt;());

    struct Point {
        x: i32,
        y: i32,
    }

    // structs
    assert_eq!(8, size_of::&lt;Point&gt;());

    // enums
    assert_eq!(8, size_of::&lt;Option&lt;i32&gt;&gt;());

    // get pointer width, will be
    // 4 bytes wide on 32-bit targets or
    // 8 bytes wide on 64-bit targets
    const WIDTH: usize = size_of::&lt;&amp;()&gt;();

    // pointers to sized types are 1 width
    assert_eq!(WIDTH, size_of::&lt;&amp;i32&gt;());
    assert_eq!(WIDTH, size_of::&lt;&amp;mut i32&gt;());
    assert_eq!(WIDTH, size_of::&lt;Box&lt;i32&gt;&gt;());
    assert_eq!(WIDTH, size_of::&lt;fn(i32) -&gt; i32&gt;());

    const DOUBLE_WIDTH: usize = 2 * WIDTH;

    // unsized struct
    struct Unsized {
        unsized_field: [i32],
    }

    // pointers to unsized types are 2 widths
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;&amp;str&gt;()); // slice
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;&amp;[i32]&gt;()); // slice
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;&amp;dyn ToString&gt;()); // trait object
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;Box&lt;dyn ToString&gt;&gt;()); // trait object
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;&amp;Unsized&gt;()); // user-defined unsized type

    // unsized types
    size_of::&lt;str&gt;(); // compile error
    size_of::&lt;[i32]&gt;(); // compile error
    size_of::&lt;dyn ToString&gt;(); // compile error
    size_of::&lt;Unsized&gt;(); // compile error
}
</code></pre></pre>
<p>How we determine the size of sized types is straight-forward: all primitives and pointers have known sizes and all structs, tuples, enums, and arrays are just made up of primitives and pointers or other nested structs, tuples, enums, and arrays so we can just count up the bytes recursively, taking into account extra bytes needed for padding and alignment. We can't determine the size of unsized types for similarly straight-forward reasons: slices can have any number of elements in them and can thus be of any size at run-time and trait objects can be implemented by any number of structs or enums and thus can also be of any size at run-time.</p>
<p><strong>Pro tips</strong></p>
<ul>
<li>pointers of dynamically sized views into arrays are called slices in Rust, e.g. a <code>&amp;str</code> is a <em>&quot;string slice&quot;</em>, a <code>&amp;[i32]</code> is an <em>&quot;i32 slice&quot;</em></li>
<li>slices are double-width because they store a pointer to the array and the number of elements in the array</li>
<li>trait object pointers are double-width because they store a pointer to the data and a pointer to a vtable</li>
<li>unsized structs pointers are double-width because they store a pointer to the struct data and the size of the struct</li>
<li>unsized structs can only have 1 unsized field and it must be the last field in the struct</li>
</ul>
<p>To really hammer home the point about double-width pointers for unsized types here's a commented code example comparing arrays to slices:</p>
<pre><pre class="playground"><code class="language-rust">use std::mem::size_of;

const WIDTH: usize = size_of::&lt;&amp;()&gt;();
const DOUBLE_WIDTH: usize = 2 * WIDTH;

fn main() {
    // data length stored in type
    // an [i32; 3] is an array of three i32s
    let nums: &amp;[i32; 3] = &amp;[1, 2, 3];

    // single-width pointer
    assert_eq!(WIDTH, size_of::&lt;&amp;[i32; 3]&gt;());

    let mut sum = 0;

    // can iterate over nums safely
    // Rust knows it's exactly 3 elements
    for num in nums {
        sum += num;
    }

    assert_eq!(6, sum);

    // unsized coercion from [i32; 3] to [i32]
    // data length now stored in pointer
    let nums: &amp;[i32] = &amp;[1, 2, 3];

    // double-width pointer required to also store data length
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;&amp;[i32]&gt;());

    let mut sum = 0;

    // can iterate over nums safely
    // Rust knows it's exactly 3 elements
    for num in nums {
        sum += num;
    }

    assert_eq!(6, sum);
}
</code></pre></pre>
<p>And here's another commented code example comparing structs to trait objects:</p>
<pre><pre class="playground"><code class="language-rust">use std::mem::size_of;

const WIDTH: usize = size_of::&lt;&amp;()&gt;();
const DOUBLE_WIDTH: usize = 2 * WIDTH;

trait Trait {
    fn print(&amp;self);
}

struct Struct;
struct Struct2;

impl Trait for Struct {
    fn print(&amp;self) {
        println!(&quot;struct&quot;);
    }
}

impl Trait for Struct2 {
    fn print(&amp;self) {
        println!(&quot;struct2&quot;);
    }
}

fn print_struct(s: &amp;Struct) {
    // always prints &quot;struct&quot;
    // this is known at compile-time
    s.print();
    // single-width pointer
    assert_eq!(WIDTH, size_of::&lt;&amp;Struct&gt;());
}

fn print_struct2(s2: &amp;Struct2) {
    // always prints &quot;struct2&quot;
    // this is known at compile-time
    s2.print();
    // single-width pointer
    assert_eq!(WIDTH, size_of::&lt;&amp;Struct2&gt;());
}

fn print_trait(t: &amp;dyn Trait) {
    // print &quot;struct&quot; or &quot;struct2&quot; ?
    // this is unknown at compile-time
    t.print();
    // Rust has to check the pointer at run-time
    // to figure out whether to use Struct's
    // or Struct2's implementation of &quot;print&quot;
    // so the pointer has to be double-width
    assert_eq!(DOUBLE_WIDTH, size_of::&lt;&amp;dyn Trait&gt;());
}

fn main() {
    // single-width pointer to data
    let s = &amp;Struct; 
    print_struct(s); // prints &quot;struct&quot;
    
    // single-width pointer to data
    let s2 = &amp;Struct2;
    print_struct2(s2); // prints &quot;struct2&quot;
    
    // unsized coercion from Struct to dyn Trait
    // double-width pointer to point to data AND Struct's vtable
    let t: &amp;dyn Trait = &amp;Struct;
    print_trait(t); // prints &quot;struct&quot;
    
    // unsized coercion from Struct2 to dyn Trait
    // double-width pointer to point to data AND Struct2's vtable
    let t: &amp;dyn Trait = &amp;Struct2;
    print_trait(t); // prints &quot;struct2&quot;
}
</code></pre></pre>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>only instances of sized types can be placed on the stack, i.e. can be passed around by value</li>
<li>instances of unsized types can't be placed on the stack and must be passed around by reference</li>
<li>pointers to unsized types are double-width because aside from pointing to data they need to do an extra bit of bookkeeping to also keep track of the data's length <em>or</em> point to a vtable</li>
</ul>
<h2 id="sized-trait"><a class="header" href="#sized-trait"><code>Sized</code> Trait</a></h2>
<p>The <code>Sized</code> trait in Rust is an auto trait and a marker trait.</p>
<p>Auto traits are traits that get automatically implemented for a type if it passes certain conditions. Marker traits are traits that mark a type as having a certain property. Marker traits do not have any trait items such as methods, associated functions, associated constants, or associated types. All auto traits are marker traits but not all marker traits are auto traits. Auto traits must be marker traits so the compiler can provide an automatic default implementation for them, which would not be possible if the trait had any trait items.</p>
<p>A type gets an auto <code>Sized</code> implementation if all of its members are also <code>Sized</code>. What &quot;members&quot; means depends on the containing type, for example: fields of a struct, variants of an enum, elements of an array, items of a tuple, and so on. Once a type has been &quot;marked&quot; with a <code>Sized</code> implementation that means its size in bytes is known at compile time.</p>
<p>Other examples of auto marker traits are the <code>Send</code> and <code>Sync</code> traits. A type is <code>Send</code> if it is safe to send that type across threads. A type is <code>Sync</code> if it's safe to share references of that type between threads. A type gets auto <code>Send</code> and <code>Sync</code> implementations if all of its members are also <code>Send</code> and <code>Sync</code>. What makes <code>Sized</code> somewhat special is that it's not possible to opt-out of unlike with the other auto marker traits which are possible to opt-out of.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span>#![feature(negative_impls)]

<span class="boring">fn main() {
</span>// this type is Sized, Send, and Sync
struct Struct;

// opt-out of Send trait
impl !Send for Struct {} // ✅

// opt-out of Sync trait
impl !Sync for Struct {} // ✅

// can't opt-out of Sized
impl !Sized for Struct {} // ❌
<span class="boring">}
</span></code></pre></pre>
<p>This seems reasonable since there might be reasons why we wouldn't want our type to be sent or shared across threads, however it's hard to imagine a scenario where we'd want the compiler to &quot;forget&quot; the size of our type and treat it as an unsized type as that offers no benefits and merely makes the type more difficult to work with.</p>
<p>Also, to be super pedantic <code>Sized</code> is not technically an auto trait since it's not defined using the <code>auto</code> keyword but the special treatment it gets from the compiler makes it behave very similarly to auto traits so in practice it's okay to think of it as an auto trait.</p>
<p><strong>Key Takeaways</strong></p>
<ul>
<li><code>Sized</code> is an &quot;auto&quot; marker trait</li>
</ul>
<h2 id="sized-in-generics"><a class="header" href="#sized-in-generics"><code>Sized</code> in Generics</a></h2>
<p>It's not immediately obvious that whenever we write any generic code every generic type parameter gets auto-bound with the <code>Sized</code> trait by default.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// this generic function...
fn func&lt;T&gt;(t: T) {}

// ...desugars to...
fn func&lt;T: Sized&gt;(t: T) {}

// ...which we can opt-out of by explicitly setting ?Sized...
fn func&lt;T: ?Sized&gt;(t: T) {} // ❌

// ...which doesn't compile since it doesn't have
// a known size so we must put it behind a pointer...
fn func&lt;T: ?Sized&gt;(t: &amp;T) {} // ✅
fn func&lt;T: ?Sized&gt;(t: Box&lt;T&gt;) {} // ✅
<span class="boring">}
</span></code></pre></pre>
<p><strong>Pro tips</strong></p>
<ul>
<li><code>?Sized</code> can be pronounced <em>&quot;optionally sized&quot;</em> or <em>&quot;maybe sized&quot;</em> and adding it to a type parameter's bounds allows the type to be sized or unsized</li>
<li><code>?Sized</code> in general is referred to as a <em>&quot;widening bound&quot;</em> or a <em>&quot;relaxed bound&quot;</em> as it relaxes rather than constrains the type parameter</li>
<li><code>?Sized</code> is the only relaxed bound in Rust</li>
</ul>
<p>So why does this matter? Well, any time we're working with a generic type and that type is behind a pointer we almost always want to opt-out of the default <code>Sized</code> bound to make our function more flexible in what argument types it will accept. Also, if we don't opt-out of the default <code>Sized</code> bound we'll eventually get some surprising and confusing compile error messages.</p>
<p>Let me take you on the journey of the first generic function I ever wrote in Rust. I started learning Rust before the <code>dbg!</code> macro landed in stable so the only way to print debug values was to type out <code>println!(&quot;{:?}&quot;, some_value);</code> every time which is pretty tedious so I decided to write a <code>debug</code> helper function like this:</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Debug;

fn debug&lt;T: Debug&gt;(t: T) { // T: Debug + Sized
    println!(&quot;{:?}&quot;, t);
}

fn main() {
    debug(&quot;my str&quot;); // T = &amp;str, &amp;str: Debug + Sized ✅
}
</code></pre></pre>
<p>So far so good, but the function takes ownership of any values passed to it which is kinda annoying so I changed the function to only take references instead:</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Debug;

fn dbg&lt;T: Debug&gt;(t: &amp;T) { // T: Debug + Sized
    println!(&quot;{:?}&quot;, t);
}

fn main() {
    dbg(&quot;my str&quot;); // &amp;T = &amp;str, T = str, str: Debug + !Sized ❌
}
</code></pre></pre>
<p>Which now throws this error:</p>
<pre><code class="language-none">error[E0277]: the size for values of type `str` cannot be known at compilation time
 --&gt; src/main.rs:8:9
  |
3 | fn dbg&lt;T: Debug&gt;(t: &amp;T) {
  |        - required by this bound in `dbg`
...
8 |     dbg(&quot;my str&quot;);
  |         ^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `str`
  = note: to learn more, visit &lt;https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait&gt;
help: consider relaxing the implicit `Sized` restriction
  |
3 | fn dbg&lt;T: Debug + ?Sized&gt;(t: &amp;T) {
  |   
</code></pre>
<p>When I first saw this I found it incredibly confusing. Despite making my function more restrictive in what arguments it takes than before it now somehow throws a compile error! What is going on?</p>
<p>I've already kinda spoiled the answer in the code comments above, but basically: Rust performs pattern matching when resolving <code>T</code> to its concrete types during compilation. Here's a couple tables to help clarify:</p>
<div class="table-wrapper"><table><thead><tr><th>Type</th><th><code>T</code></th><th><code>&amp;T</code></th></tr></thead><tbody>
<tr><td><code>&amp;str</code></td><td><code>T</code> = <code>&amp;str</code></td><td><code>T</code> = <code>str</code></td></tr>
</tbody></table>
</div><div class="table-wrapper"><table><thead><tr><th>Type</th><th><code>Sized</code></th></tr></thead><tbody>
<tr><td><code>str</code></td><td>❌</td></tr>
<tr><td><code>&amp;str</code></td><td>✅</td></tr>
<tr><td><code>&amp;&amp;str</code></td><td>✅</td></tr>
</tbody></table>
</div>
<p>This is why I had to add a <code>?Sized</code> bound to make the function work as intended after changing it to take references. The working function below:</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Debug;

fn debug&lt;T: Debug + ?Sized&gt;(t: &amp;T) { // T: Debug + ?Sized
    println!(&quot;{:?}&quot;, t);
}

fn main() {
    debug(&quot;my str&quot;); // &amp;T = &amp;str, T = str, str: Debug + !Sized ✅
}
</code></pre></pre>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>all generic type parameters are auto-bound with <code>Sized</code> by default</li>
<li>if we have a generic function which takes an argument of some <code>T</code> behind a pointer, e.g. <code>&amp;T</code>, <code>Box&lt;T&gt;</code>, <code>Rc&lt;T&gt;</code>, et cetera, then we almost always want to opt-out of the default <code>Sized</code> bound with <code>T: ?Sized</code></li>
</ul>
<h2 id="unsized-types"><a class="header" href="#unsized-types">Unsized Types</a></h2>
<h3 id="slices"><a class="header" href="#slices">Slices</a></h3>
<p>The most common slices are string slices <code>&amp;str</code> and array slices <code>&amp;[T]</code>. What's nice about slices is that many other types coerce to them, so leveraging slices and Rust's auto type coercions allow us to write flexible APIs.</p>
<p>Type coercions can happen in several places but most notably on function arguments and at method calls. The kinds of type coercions we're interested in are deref coercions and unsized coercions. A deref coercion is when a <code>T</code> gets coerced into a <code>U</code> following a deref operation, i.e. <code>T: Deref&lt;Target = U&gt;</code>, e.g. <code>String.deref() -&gt; str</code>. An unsized coercion is when a <code>T</code> gets coerced into a <code>U</code> where <code>T</code> is a sized type and <code>U</code> is an unsized type, i.e. <code>T: Unsize&lt;U&gt;</code>, e.g. <code>[i32; 3] -&gt; [i32]</code>.</p>
<pre><pre class="playground"><code class="language-rust">trait Trait {
    fn method(&amp;self) {}
}

impl Trait for str {
    // can now call &quot;method&quot; on
    // 1) str or
    // 2) String since String: Deref&lt;Target = str&gt;
}
impl&lt;T&gt; Trait for [T] {
    // can now call &quot;method&quot; on
    // 1) any &amp;[T]
    // 2) any U where U: Deref&lt;Target = [T]&gt;, e.g. Vec&lt;T&gt;
    // 3) [T; N] for any N, since [T; N]: Unsize&lt;[T]&gt;
}

fn str_fun(s: &amp;str) {}
fn slice_fun&lt;T&gt;(s: &amp;[T]) {}

fn main() {
    let str_slice: &amp;str = &quot;str slice&quot;;
    let string: String = &quot;string&quot;.to_owned();

    // function args
    str_fun(str_slice);
    str_fun(&amp;string); // deref coercion

    // method calls
    str_slice.method();
    string.method(); // deref coercion

    let slice: &amp;[i32] = &amp;[1];
    let three_array: [i32; 3] = [1, 2, 3];
    let five_array: [i32; 5] = [1, 2, 3, 4, 5];
    let vec: Vec&lt;i32&gt; = vec![1];

    // function args
    slice_fun(slice);
    slice_fun(&amp;vec); // deref coercion
    slice_fun(&amp;three_array); // unsized coercion
    slice_fun(&amp;five_array); // unsized coercion

    // method calls
    slice.method();
    vec.method(); // deref coercion
    three_array.method(); // unsized coercion
    five_array.method(); // unsized coercion
}
</code></pre></pre>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>leveraging slices and Rust's auto type coercions allows us to write flexible APIs</li>
</ul>
<h3 id="trait-objects"><a class="header" href="#trait-objects">Trait Objects</a></h3>
<p>Traits are <code>?Sized</code> by default. This program:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait: ?Sized {}
<span class="boring">}
</span></code></pre></pre>
<p>Throws this error:</p>
<pre><code class="language-none">error: `?Trait` is not permitted in supertraits
 --&gt; src/main.rs:1:14
  |
1 | trait Trait: ?Sized {}
  |              ^^^^^^
  |
  = note: traits are `?Sized` by default
</code></pre>
<p>We'll get into why traits are <code>?Sized</code> by default soon but first let's ask ourselves what are the implications of a trait being <code>?Sized</code>? Let's desugar the above example:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait where Self: ?Sized {}
<span class="boring">}
</span></code></pre></pre>
<p>Okay, so by default traits allow <code>self</code> to possibly be an unsized type. As we learned earlier we can't pass unsized types around by value, so that limits us in the kind of methods we can define in the trait. It should be impossible to write a method the takes or returns <code>self</code> by value and yet this surprisingly compiles:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {
    fn method(self); // ✅
}
<span class="boring">}
</span></code></pre></pre>
<p>However the moment we try to implement the method, either by providing a default implementation or by implementing the trait for an unsized type, we get compile errors:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {
    fn method(self) {} // ❌
}

impl Trait for str {
    fn method(self) {} // ❌
}
<span class="boring">}
</span></code></pre></pre>
<p>Throws:</p>
<pre><code class="language-none">error[E0277]: the size for values of type `Self` cannot be known at compilation time
 --&gt; src/lib.rs:2:15
  |
2 |     fn method(self) {}
  |               ^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `Self`
  = note: to learn more, visit &lt;https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait&gt;
  = note: all local variables must have a statically known size
  = help: unsized locals are gated as an unstable feature
help: consider further restricting `Self`
  |
2 |     fn method(self) where Self: std::marker::Sized {}
  |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the size for values of type `str` cannot be known at compilation time
 --&gt; src/lib.rs:6:15
  |
6 |     fn method(self) {}
  |               ^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `str`
  = note: to learn more, visit &lt;https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait&gt;
  = note: all local variables must have a statically known size
  = help: unsized locals are gated as an unstable feature
</code></pre>
<p>If we're determined to pass <code>self</code> around by value we can fix the first error by explicitly binding the trait with <code>Sized</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait: Sized {
    fn method(self) {} // ✅
}

impl Trait for str { // ❌
    fn method(self) {}
}
<span class="boring">}
</span></code></pre></pre>
<p>Now throws:</p>
<pre><code class="language-none">error[E0277]: the size for values of type `str` cannot be known at compilation time
 --&gt; src/lib.rs:7:6
  |
1 | trait Trait: Sized {
  |              ----- required by this bound in `Trait`
...
7 | impl Trait for str {
  |      ^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `str`
  = note: to learn more, visit &lt;https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait&gt;
</code></pre>
<p>Which is okay, as we knew upon binding the trait with <code>Sized</code> we'd no longer be able to implement it for unsized types such as <code>str</code>. If on the other hand we really wanted to implement the trait for <code>str</code> an alternative solution would be to keep the trait <code>?Sized</code> and pass <code>self</code> around by reference:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {
    fn method(&amp;self) {} // ✅
}

impl Trait for str {
    fn method(&amp;self) {} // ✅
}
<span class="boring">}
</span></code></pre></pre>
<p>Instead of marking the entire trait as <code>?Sized</code> or <code>Sized</code> we have the more granular and precise option of marking individual methods as <code>Sized</code> like so:</p>
<pre><pre class="playground"><code class="language-rust">trait Trait {
    fn method(self) where Self: Sized {}
}

impl Trait for str {} // ✅!?

fn main() {
    &quot;str&quot;.method(); // ❌
}
</code></pre></pre>
<p>It's surprising that Rust compiles <code>impl Trait for str {}</code> without any complaints, but it eventually catches the error when we attempt to call <code>method</code> on an unsized type so all is fine. It's a little weird but affords us some flexibility in implementing traits with some <code>Sized</code> methods for unsized types as long as we never call the <code>Sized</code> methods:</p>
<pre><pre class="playground"><code class="language-rust">trait Trait {
    fn method(self) where Self: Sized {}
    fn method2(&amp;self) {}
}

impl Trait for str {} // ✅

fn main() {
    // we never call &quot;method&quot; so no errors
    &quot;str&quot;.method2(); // ✅
}
</code></pre></pre>
<p>Now back to the original question, why are traits <code>?Sized</code> by default? The answer is trait objects. Trait objects are inherently unsized because any type of any size can implement a trait, therefore we can only implement <code>Trait</code> for <code>dyn Trait</code> if <code>Trait: ?Sized</code>. To put it in code:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait: ?Sized {}

// the above is REQUIRED for

impl Trait for dyn Trait {
    // compiler magic here
}

// since `dyn Trait` is unsized

// and now we can use `dyn Trait` in our program

fn function(t: &amp;dyn Trait) {} // ✅
<span class="boring">}
</span></code></pre></pre>
<p>If we try to actually compile the above program we get:</p>
<pre><code class="language-none">error[E0371]: the object type `(dyn Trait + 'static)` automatically implements the trait `Trait`
 --&gt; src/lib.rs:5:1
  |
5 | impl Trait for dyn Trait {
  | ^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Trait + 'static)` automatically implements trait `Trait`
</code></pre>
<p>Which is the compiler telling us to chill since it automatically provides the implementation of <code>Trait</code> for <code>dyn Trait</code>. Again, since <code>dyn Trait</code> is unsized the compiler can only provide this implementation if <code>Trait: ?Sized</code>. If we bound <code>Trait</code> by <code>Sized</code> then <code>Trait</code> becomes <em>&quot;object unsafe&quot;</em> which is a term that means we can't cast types which implement <code>Trait</code> to trait objects of <code>dyn Trait</code>. As expected this program does not compile:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait: Sized {}

fn function(t: &amp;dyn Trait) {} // ❌
<span class="boring">}
</span></code></pre></pre>
<p>Throws:</p>
<pre><code class="language-none">error[E0038]: the trait `Trait` cannot be made into an object
 --&gt; src/lib.rs:3:18
  |
1 | trait Trait: Sized {}
  |       -----  ----- ...because it requires `Self: Sized`
  |       |
  |       this trait cannot be made into an object...
2 | 
3 | fn function(t: &amp;dyn Trait) {}
  |                ^^^^^^^^^^ the trait `Trait` cannot be made into an object
</code></pre>
<p>Let's try to make an <code>?Sized</code> trait with a <code>Sized</code> method and see if we can cast it to a trait object:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {
    fn method(self) where Self: Sized {}
    fn method2(&amp;self) {}
}

fn function(arg: &amp;dyn Trait) { // ✅
    arg.method(); // ❌
    arg.method2(); // ✅
}
<span class="boring">}
</span></code></pre></pre>
<p>As we saw before everything is okay as long as we don't call the <code>Sized</code> method on the trait object.</p>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>all traits are <code>?Sized</code> by default</li>
<li><code>Trait: ?Sized</code> is required for <code>impl Trait for dyn Trait</code></li>
<li>we can require <code>Self: Sized</code> on a per-method basis</li>
<li>traits bound by <code>Sized</code> can't be made into trait objects</li>
</ul>
<h3 id="trait-object-limitations"><a class="header" href="#trait-object-limitations">Trait Object Limitations</a></h3>
<p>Even if a trait is object-safe there are still sizedness-related edge cases which limit what types can be cast to trait objects and how many and what kind of traits can be represented by a trait object.</p>
<h4 id="cannot-cast-unsized-types-to-trait-objects"><a class="header" href="#cannot-cast-unsized-types-to-trait-objects">Cannot Cast Unsized Types to Trait Objects</a></h4>
<pre><pre class="playground"><code class="language-rust">fn generic&lt;T: ToString&gt;(t: T) {}
fn trait_object(t: &amp;dyn ToString) {}

fn main() {
    generic(String::from(&quot;String&quot;)); // ✅
    generic(&quot;str&quot;); // ✅
    trait_object(&amp;String::from(&quot;String&quot;)); // ✅ - unsized coercion
    trait_object(&quot;str&quot;); // ❌ - unsized coercion impossible
}
</code></pre></pre>
<p>Throws:</p>
<pre><code class="language-none">error[E0277]: the size for values of type `str` cannot be known at compilation time
 --&gt; src/main.rs:8:18
  |
8 |     trait_object(&quot;str&quot;);
  |                  ^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `str`
  = note: to learn more, visit &lt;https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait&gt;
  = note: required for the cast to the object type `dyn std::string::ToString`
</code></pre>
<p>The reason why passing a <code>&amp;String</code> to a function expecting a <code>&amp;dyn ToString</code> works is because of type coercion. <code>String</code> implements <code>ToString</code> and we can convert a sized type such as <code>String</code> into an unsized type such as <code>dyn ToString</code> via an unsized coercion. <code>str</code> also implements <code>ToString</code> and converting <code>str</code> into a <code>dyn ToString</code> would also require an unsized coercion but <code>str</code> is already unsized! How do we unsize an already unsized type into another unsized type?</p>
<p><code>&amp;str</code> pointers are double-width, storing a pointer to the data and the data length. <code>&amp;dyn ToString</code> pointers are also double-width, storing a pointer to the data and a pointer to a vtable. To coerce a <code>&amp;str</code> into a <code>&amp;dyn toString</code> would require a triple-width pointer to store a pointer to the data, the data length, and a pointer to a vtable. Rust does not support triple-width pointers so casting an unsized type to a trait object is not possible.</p>
<p>Previous two paragraphs summarized in a table:</p>
<div class="table-wrapper"><table><thead><tr><th>Type</th><th>Pointer to Data</th><th>Data Length</th><th>Pointer to VTable</th><th>Total Width</th></tr></thead><tbody>
<tr><td><code>&amp;String</code></td><td>✅</td><td>❌</td><td>❌</td><td>1 ✅</td></tr>
<tr><td><code>&amp;str</code></td><td>✅</td><td>✅</td><td>❌</td><td>2 ✅</td></tr>
<tr><td><code>&amp;String as &amp;dyn ToString</code></td><td>✅</td><td>❌</td><td>✅</td><td>2 ✅</td></tr>
<tr><td><code>&amp;str as &amp;dyn ToString</code></td><td>✅</td><td>✅</td><td>✅</td><td>3 ❌</td></tr>
</tbody></table>
</div>
<h4 id="cannot-create-multi-trait-objects"><a class="header" href="#cannot-create-multi-trait-objects">Cannot create Multi-Trait Objects</a></h4>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {}
trait Trait2 {}

fn function(t: &amp;(dyn Trait + Trait2)) {}
<span class="boring">}
</span></code></pre></pre>
<p>Throws:</p>
<pre><code class="language-none">error[E0225]: only auto traits can be used as additional traits in a trait object
 --&gt; src/lib.rs:4:30
  |
4 | fn function(t: &amp;(dyn Trait + Trait2)) {}
  |                      -----   ^^^^^^
  |                      |       |
  |                      |       additional non-auto trait
  |                      |       trait alias used in trait object type (additional use)
  |                      first non-auto trait
  |                      trait alias used in trait object type (first use)
</code></pre>
<p>Remember that a trait object pointer is double-width: storing 1 pointer to the data and another to the vtable, but there's 2 traits here so there's 2 vtables which would require the <code>&amp;(dyn Trait + Trait2)</code> pointer to be 3 widths. Auto-traits like <code>Sync</code> and <code>Send</code> are allowed since they don't have methods and thus don't have vtables.</p>
<p>The workaround for this is to combine vtables by combining the traits using another trait like so:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {
    fn method(&amp;self) {}
}

trait Trait2 {
    fn method2(&amp;self) {}
}

trait Trait3: Trait + Trait2 {}

// auto blanket impl Trait3 for any type that also impls Trait &amp; Trait2
impl&lt;T: Trait + Trait2&gt; Trait3 for T {}

// from `dyn Trait + Trait2` to `dyn Trait3` 
fn function(t: &amp;dyn Trait3) {
    t.method(); // ✅
    t.method2(); // ✅
}
<span class="boring">}
</span></code></pre></pre>
<p>One downside of this workaround is that Rust does not support supertrait upcasting. What this means is that if we have a <code>dyn Trait3</code> we can't use it where we need a <code>dyn Trait</code> or a <code>dyn Trait2</code>. This program does not compile:</p>
<pre><pre class="playground"><code class="language-rust">trait Trait {
    fn method(&amp;self) {}
}

trait Trait2 {
    fn method2(&amp;self) {}
}

trait Trait3: Trait + Trait2 {}

impl&lt;T: Trait + Trait2&gt; Trait3 for T {}

struct Struct;
impl Trait for Struct {}
impl Trait2 for Struct {}

fn takes_trait(t: &amp;dyn Trait) {}
fn takes_trait2(t: &amp;dyn Trait2) {}

fn main() {
    let t: &amp;dyn Trait3 = &amp;Struct;
    takes_trait(t); // ❌
    takes_trait2(t); // ❌
}
</code></pre></pre>
<p>Throws:</p>
<pre><code class="language-none">error[E0308]: mismatched types
  --&gt; src/main.rs:22:17
   |
22 |     takes_trait(t);
   |                 ^ expected trait `Trait`, found trait `Trait3`
   |
   = note: expected reference `&amp;dyn Trait`
              found reference `&amp;dyn Trait3`

error[E0308]: mismatched types
  --&gt; src/main.rs:23:18
   |
23 |     takes_trait2(t);
   |                  ^ expected trait `Trait2`, found trait `Trait3`
   |
   = note: expected reference `&amp;dyn Trait2`
              found reference `&amp;dyn Trait3`
</code></pre>
<p>This is because <code>dyn Trait3</code> is a distinct type from <code>dyn Trait</code> and <code>dyn Trait2</code> in the sense that they have different vtable layouts, although <code>dyn Trait3</code> does contain all the methods of <code>dyn Trait</code> and <code>dyn Trait2</code>. The workaround here is to add explicit casting methods:</p>
<pre><pre class="playground"><code class="language-rust">trait Trait {}
trait Trait2 {}

trait Trait3: Trait + Trait2 {
    fn as_trait(&amp;self) -&gt; &amp;dyn Trait;
    fn as_trait2(&amp;self) -&gt; &amp;dyn Trait2;
}

impl&lt;T: Trait + Trait2&gt; Trait3 for T {
    fn as_trait(&amp;self) -&gt; &amp;dyn Trait {
        self
    }
    fn as_trait2(&amp;self) -&gt; &amp;dyn Trait2 {
        self
    }
}

struct Struct;
impl Trait for Struct {}
impl Trait2 for Struct {}

fn takes_trait(t: &amp;dyn Trait) {}
fn takes_trait2(t: &amp;dyn Trait2) {}

fn main() {
    let t: &amp;dyn Trait3 = &amp;Struct;
    takes_trait(t.as_trait()); // ✅
    takes_trait2(t.as_trait2()); // ✅
}
</code></pre></pre>
<p>This is a simple and straight-forward workaround that seems like something the Rust compiler could automate for us. Rust is not shy about performing type coercions as we have seen with deref and unsized coercions, so why isn't there a trait upcasting coercion? This is a good question with a familiar answer: the Rust core team is working on other higher-priority and higher-impact features. Fair enough.</p>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>Rust doesn't support pointers wider than 2 widths so
<ul>
<li>we can't cast unsized types to trait objects</li>
<li>we can't have multi-trait objects, but we can work around this by coalescing multiple traits into a single trait</li>
</ul>
</li>
</ul>
<h3 id="user-defined-unsized-types"><a class="header" href="#user-defined-unsized-types">User-Defined Unsized Types</a></h3>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Unsized {
    unsized_field: [i32],
}
<span class="boring">}
</span></code></pre></pre>
<p>We can define an unsized struct by giving the struct an unsized field. Unsized structs can only have 1 unsized field and it must be the last field in the struct. This is a requirement so that the compiler can determine the starting offset of every field in the struct at compile-time, which is important for efficient and fast field access. Furthermore, a single unsized field is the most that can be tracked using a double-width pointer, as more unsized fields would require more widths.</p>
<p>So how do we even instantiate this thing? The same way we do with any unsized type: by first making a sized version of it then coercing it into the unsized version. However, <code>Unsized</code> is always unsized by definition, there's no way to make a sized version of it! The only workaround is to make the struct generic so that it can exist in both sized and unsized versions:</p>
<pre><pre class="playground"><code class="language-rust">struct MaybeSized&lt;T: ?Sized&gt; {
    maybe_sized: T,
}

fn main() {
    // unsized coercion from MaybeSized&lt;[i32; 3]&gt; to MaybeSized&lt;[i32]&gt;
    let ms: &amp;MaybeSized&lt;[i32]&gt; = &amp;MaybeSized { maybe_sized: [1, 2, 3] };
}
</code></pre></pre>
<p>So what are the use-cases of this? There aren't any particularly compelling ones, user-defined unsized types are a pretty half-baked feature right now and their limitations outweigh any benefits. They're mentioned here purely for the sake of comprehensiveness.</p>
<p><strong>Fun fact:</strong> <code>std::ffi::OsStr</code> and <code>std::path::Path</code> are 2 unsized structs in the standard library that you've probably used before without realizing!</p>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>user-defined unsized types are a half-baked feature right now and their limitations outweigh any benefits</li>
</ul>
<h2 id="zero-sized-types"><a class="header" href="#zero-sized-types">Zero-Sized Types</a></h2>
<p>ZSTs sound exotic at first but they're used everywhere.</p>
<h3 id="unit-type"><a class="header" href="#unit-type">Unit Type</a></h3>
<p>The most common ZST is the unit type: <code>()</code>. All empty blocks <code>{}</code> evaluate to <code>()</code> and if the block is non-empty but the last expression is discarded with a semicolon <code>;</code> then it also evaluates to <code>()</code>. Example:</p>
<pre><pre class="playground"><code class="language-rust">fn main() {
    let a: () = {};
    let b: i32 = {
        5
    };
    let c: () = {
        5;
    };
}
</code></pre></pre>
<p>Every function which doesn't have an explicit return type returns <code>()</code> by default.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// with sugar
fn function() {}

// desugared
fn function() -&gt; () {}
<span class="boring">}
</span></code></pre></pre>
<p>Since <code>()</code> is zero bytes all instances of <code>()</code> are the same which makes for some really simple <code>Default</code>, <code>PartialEq</code>, and <code>Ord</code> implementations:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::cmp::Ordering;

impl Default for () {
    fn default() {}
}

impl PartialEq for () {
    fn eq(&amp;self, _other: &amp;()) -&gt; bool {
        true
    }
    fn ne(&amp;self, _other: &amp;()) -&gt; bool {
        false
    }
}

impl Ord for () {
    fn cmp(&amp;self, _other: &amp;()) -&gt; Ordering {
        Ordering::Equal
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>The compiler understands <code>()</code> is zero-sized and optimizes away interactions with instances of <code>()</code>. For example, a <code>Vec&lt;()&gt;</code> will never make any heap allocations, and pushing and popping <code>()</code> from the <code>Vec</code> just increments and decrements its <code>len</code> field:</p>
<pre><pre class="playground"><code class="language-rust">fn main() {
    // zero capacity is all the capacity we need to &quot;store&quot; infinitely many ()
    let mut vec: Vec&lt;()&gt; = Vec::with_capacity(0);
    // causes no heap allocations or vec capacity changes
    vec.push(()); // len++
    vec.push(()); // len++
    vec.push(()); // len++
    vec.pop(); // len--
    assert_eq!(2, vec.len());
}
</code></pre></pre>
<p>The above example has no practical applications, but is there any situation where we can take advantage of the above idea in a meaningful way? Surprisingly yes, we can get an efficient <code>HashSet&lt;Key&gt;</code> implementation from a <code>HashMap&lt;Key, Value&gt;</code> by setting the <code>Value</code> to <code>()</code> which is exactly how <code>HashSet</code> in the Rust standard library works:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// std::collections::HashSet
pub struct HashSet&lt;T&gt; {
    map: HashMap&lt;T, ()&gt;,
}
<span class="boring">}
</span></code></pre></pre>
<p><strong>Key Takeaways</strong></p>
<ul>
<li>all instances of a ZST are equal to each other</li>
<li>Rust compiler knows to optimize away interactions with ZSTs</li>
</ul>
<h3 id="user-defined-unit-structs"><a class="header" href="#user-defined-unit-structs">User-Defined Unit Structs</a></h3>
<p>A unit struct is any struct without any fields, e.g.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Struct;
<span class="boring">}
</span></code></pre></pre>
<p>Properties that make unit structs more useful than <code>()</code>:</p>
<ul>
<li>we can implement whatever traits we want on our own unit structs, Rust's trait orphan rules prevent us from implementing traits for <code>()</code> as it's defined in the standard library</li>
<li>unit structs can be given meaningful names within the context of our program</li>
<li>unit structs, like all structs, are non-Copy by default, which may be important in the context of our program</li>
</ul>
<h3 id="never-type"><a class="header" href="#never-type">Never Type</a></h3>
<p>The second most common ZST is the never type: <code>!</code>. It's called the never type because it represents computations that never resolve to any value at all.</p>
<p>A couple interesting properties of <code>!</code> that make it different from <code>()</code>:</p>
<ul>
<li><code>!</code> can be coerced into any other type</li>
<li>it's not possible to create instances of <code>!</code></li>
</ul>
<p>The first interesting property is very useful for ergonomics and allows us to use handy macros like these:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// nice for quick prototyping
fn example&lt;T&gt;(t: &amp;[T]) -&gt; Vec&lt;T&gt; {
    unimplemented!() // ! coerced to Vec&lt;T&gt;
}

fn example2() -&gt; i32 {
    // we know this parse call will never fail
    match &quot;123&quot;.parse::&lt;i32&gt;() {
        Ok(num) =&gt; num,
        Err(_) =&gt; unreachable!(), // ! coerced to i32
    }
}

fn example3(some_condition: bool) -&gt; &amp;'static str {
    if !some_condition {
        panic!() // ! coerced to &amp;str
    } else {
        &quot;str&quot;
    }
}
<span class="boring">}
</span></code></pre></pre>
<p><code>break</code>, <code>continue</code>, and <code>return</code> expressions also have type <code>!</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn example() -&gt; i32 {
    // we can set the type of x to anything here
    // since the block never evaluates to any value
    let x: String = {
        return 123 // ! coerced to String
    };
}

fn example2(nums: &amp;[i32]) -&gt; Vec&lt;i32&gt; {
    let mut filtered = Vec::new();
    for num in nums {
        filtered.push(
            if *num &lt; 0 {
                break // ! coerced to i32
            } else if *num % 2 == 0 {
                *num
            } else {
                continue // ! coerced to i32
            }
        );
    }
    filtered
}
<span class="boring">}
</span></code></pre></pre>
<p>The second interesting property of <code>!</code> allows us to mark certain states as impossible on a type level. Let's take this function signature as an example:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn function() -&gt; Result&lt;Success, Error&gt;;
<span class="boring">}
</span></code></pre></pre>
<p>We know that if the function returns and was successful the <code>Result</code> will contain some instance of type <code>Success</code> and if it errored <code>Result</code> will contain some instance of type <code>Error</code>. Now let's compare that to this function signature:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn function() -&gt; Result&lt;Success, !&gt;;
<span class="boring">}
</span></code></pre></pre>
<p>We know that if the function returns and was successful the <code>Result</code> will hold some instance of type <code>Success</code> and if it errored... but wait, it can never error, since it's impossible to create instances of <code>!</code>. Given the above function signature we know this function will never error. How about this function signature:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn function() -&gt; Result&lt;!, Error&gt;;
<span class="boring">}
</span></code></pre></pre>
<p>The inverse of the previous is now true: if this function returns we know it must have errored as success is impossible.</p>
<p>A practical application of the former example would be the <code>FromStr</code> implementation for <code>String</code> as it's impossible to fail converting a <code>&amp;str</code> into a <code>String</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span>#![feature(never_type)]

<span class="boring">fn main() {
</span>use std::str::FromStr;

impl FromStr for String {
    type Err = !;
    fn from_str(s: &amp;str) -&gt; Result&lt;String, Self::Err&gt; {
        Ok(String::from(s))
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>A practical application of the latter example would be a function that runs an infinite loop that's never meant to return, like a server responding to client requests, unless there's some error:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span>#![feature(never_type)]

<span class="boring">fn main() {
</span>fn run_server() -&gt; Result&lt;!, ConnectionError&gt; {
    loop {
        let (request, response) = get_request()?;
        let result = request.process();
        response.send(result);
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>The feature flag is necessary because while the never type exists and works within Rust internals using it in user-code is still considered experimental.</p>
<p><strong>Key Takeaways</strong></p>
<ul>
<li><code>!</code> can be coerced into any other type</li>
<li>it's not possible to create instances of <code>!</code> which we can use to mark certain states as impossible at a type level</li>
</ul>
<h3 id="user-defined-pseudo-never-types"><a class="header" href="#user-defined-pseudo-never-types">User-Defined Pseudo Never Types</a></h3>
<p>While it's not possible to define a type that can coerce to any other type it is possible to define a type which is impossible to create instances of such as an <code>enum</code> without any variants:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Void {}
<span class="boring">}
</span></code></pre></pre>
<p>This allows us to remove the feature flag from the previous two examples and implement them using stable Rust:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Void {}

// example 1
impl FromStr for String {
    type Err = Void;
    fn from_str(s: &amp;str) -&gt; Result&lt;String, Self::Err&gt; {
        Ok(String::from(s))
    }
}

// example 2
fn run_server() -&gt; Result&lt;Void, ConnectionError&gt; {
    loop {
        let (request, response) = get_request()?;
        let result = request.process();
        response.send(result);
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>This is the technique the Rust standard library uses, as the <code>Err</code> type for the <code>FromStr</code> implementation of <code>String</code> is <code>std::convert::Infallible</code> which is defined as:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub enum Infallible {}
<span class="boring">}
</span></code></pre></pre>
<h3 id="phantomdata"><a class="header" href="#phantomdata">PhantomData</a></h3>
<p>The third most commonly used ZST is probably <code>PhantomData</code>. <code>PhantomData</code> is a zero-sized marker struct which can be used to &quot;mark&quot; a containing struct as having certain properties. It's similar in purpose to its auto marker trait cousins such as <code>Sized</code>, <code>Send</code>, and <code>Sync</code> but being a marker struct is used a little bit differently. Giving a thorough explanation of <code>PhantomData</code> and exploring all of its use-cases is outside the scope of this article so let's only briefly go over a single simple example. Recall this code snippet presented earlier:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span>#![feature(negative_impls)]

<span class="boring">fn main() {
</span>// this type is Send and Sync
struct Struct;

// opt-out of Send trait
impl !Send for Struct {}

// opt-out of Sync trait
impl !Sync for Struct {}
<span class="boring">}
</span></code></pre></pre>
<p>It's unfortunate that we have to use a feature flag, can we accomplish the same result using only stable Rust? As we've learned, a type is only <code>Send</code> and <code>Sync</code> if all of its members are also <code>Send</code> and <code>Sync</code>, so we can add a <code>!Send</code> and <code>!Sync</code> member to <code>Struct</code> like <code>Rc&lt;()&gt;</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::rc::Rc;

// this type is not Send or Sync
struct Struct {
    // adds 8 bytes to every instance
    _not_send_or_sync: Rc&lt;()&gt;,
}
<span class="boring">}
</span></code></pre></pre>
<p>This is less than ideal because it adds size to every instance of <code>Struct</code> and we now also have to conjure a <code>Rc&lt;()&gt;</code> from thin air every time we want to create a <code>Struct</code>. Since <code>PhantomData</code> is a ZST it solves both of these problems:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::rc::Rc;
use std::marker::PhantomData;

type NotSendOrSyncPhantom = PhantomData&lt;Rc&lt;()&gt;&gt;;

// this type is not Send or Sync
struct Struct {
    // adds no additional size to instances
    _not_send_or_sync: NotSendOrSyncPhantom,
}
<span class="boring">}
</span></code></pre></pre>
<p><strong>Key Takeaways</strong></p>
<ul>
<li><code>PhantomData</code> is a zero-sized marker struct which can be used to &quot;mark&quot; a containing struct as having certain properties</li>
</ul>
<h2 id="conclusion"><a class="header" href="#conclusion">Conclusion</a></h2>
<ul>
<li>only instances of sized types can be placed on the stack, i.e. can be passed around by value</li>
<li>instances of unsized types can't be placed on the stack and must be passed around by reference</li>
<li>pointers to unsized types are double-width because aside from pointing to data they need to do an extra bit of bookkeeping to also keep track of the data's length <em>or</em> point to a vtable</li>
<li><code>Sized</code> is an &quot;auto&quot; marker trait</li>
<li>all generic type parameters are auto-bound with <code>Sized</code> by default</li>
<li>if we have a generic function which takes an argument of some <code>T</code> behind a pointer, e.g. <code>&amp;T</code>, <code>Box&lt;T&gt;</code>, <code>Rc&lt;T&gt;</code>, et cetera, then we almost always want to opt-out of the default <code>Sized</code> bound with <code>T: ?Sized</code></li>
<li>leveraging slices and Rust's auto type coercions allows us to write flexible APIs</li>
<li>all traits are <code>?Sized</code> by default</li>
<li><code>Trait: ?Sized</code> is required for <code>impl Trait for dyn Trait</code></li>
<li>we can require <code>Self: Sized</code> on a per-method basis</li>
<li>traits bound by <code>Sized</code> can't be made into trait objects</li>
<li>Rust doesn't support pointers wider than 2 widths so
<ul>
<li>we can't cast unsized types to trait objects</li>
<li>we can't have multi-trait objects, but we can work around this by coalescing multiple traits into a single trait</li>
</ul>
</li>
<li>user-defined unsized types are a half-baked feature right now and their limitations outweigh any benefits</li>
<li>all instances of a ZST are equal to each other</li>
<li>Rust compiler knows to optimize away interactions with ZSTs</li>
<li><code>!</code> can be coerced into any other type</li>
<li>it's not possible to create instances of <code>!</code> which we can use to mark certain states as impossible at a type level</li>
<li><code>PhantomData</code> is a zero-sized marker struct which can be used to &quot;mark&quot; a containing struct as having certain properties</li>
</ul>
<h2 id="discuss"><a class="header" href="#discuss">Discuss</a></h2>
<p>Discuss this article on</p>
<ul>
<li><a href="https://users.rust-lang.org/t/blog-post-sizedness-in-rust/46293?u=pretzelhammer">official Rust users forum</a></li>
<li><a href="https://www.reddit.com/r/learnrust/comments/hx2jd0/sizedness_in_rust/">learnrust subreddit</a></li>
<li><a href="https://twitter.com/pretzelhammer/status/1286669073137491973">Twitter</a></li>
<li><a href="https://www.reddit.com/r/rust/comments/hxips7/sizedness_in_rust/">rust subreddit</a></li>
<li><a href="https://github.com/pretzelhammer/rust-blog/discussions">Github</a></li>
</ul>
<h2 id="notifications"><a class="header" href="#notifications">Notifications</a></h2>
<p>Get notified when the next article get published by</p>
<ul>
<li><a href="https://twitter.com/pretzelhammer">Following pretzelhammer on Twitter</a> or</li>
<li><a href="https://github.com/pretzelhammer/rust-blog/releases.atom">Subscribing to this repo's release RSS feed</a> or</li>
<li>Watching this repo's releases (click <code>Watch</code> -&gt; click <code>Custom</code> -&gt; select <code>Releases</code> -&gt; click <code>Apply</code>)</li>
</ul>
<h2 id="further-reading"><a class="header" href="#further-reading">Further Reading</a></h2>
<ul>
<li><a href="./common-rust-lifetime-misconceptions.html">Common Rust Lifetime Misconceptions</a></li>
<li><a href="./tour-of-rusts-standard-library-traits.html">Tour of Rust's Standard Library Traits</a></li>
<li><a href="./restful-api-in-sync-and-async-rust.html">RESTful API in Sync &amp; Async Rust</a></li>
<li><a href="./learning-rust-in-2020.html">Learning Rust in 2020</a></li>
<li><a href="./too-many-brainfuck-compilers.html">Learn Assembly with Entirely Too Many Brainfuck Compilers</a></li>
</ul>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../../01_类型系统/定海神针Pin和Unpin/定海神针Pin和Unpin.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>

                            <a rel="next" href="../../01_类型系统/Rust生命周期集大成者PhantomData〈T〉/Rust生命周期集大成者PhantomData〈T〉.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../../01_类型系统/定海神针Pin和Unpin/定海神针Pin和Unpin.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>

                    <a rel="next" href="../../01_类型系统/Rust生命周期集大成者PhantomData〈T〉/Rust生命周期集大成者PhantomData〈T〉.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="../../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="../../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->


    </body>
</html>
